/*
 *  Copyright 2009 Lucas Nazário dos Santos
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package net.sourceforge.retriever.fetcher;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import sun.net.www.protocol.http.HttpURLConnection;
import sun.net.www.protocol.https.HttpsURLConnectionImpl;

/**
 * This class is a representation of HTTP resources.
 */
public class HTTPFetcher extends Fetcher {


	/**
	 * TODO Write javadoc.
	 */
	public HTTPFetcher(final URL url) {
		super(url);
	}

	/**
	 * Returns a list containing all URLs hyperlinked by this one.
	 * 
	 * @param charset To correctly retrieve the URL's hyperlinks.
	 * @return A list containing all URLs hyperlinked by this one.
	 */
	@Override
	public List<String> getInnerURLs(final String charset) {
		final List<String> result = new ArrayList<String>();

		try {
			super.resetInputStream();

			final StringBuilder content = new StringBuilder();
			this.parseInputStreamIntoStringBuilder(content, charset);

			final Pattern linkPattern = Pattern.compile("(?<=((href|src|location)\\s{0,10}=\\s{0,10}(\'|\")?))([^\'\"> ]+)", Pattern.CASE_INSENSITIVE);
			final Matcher linkMatcher = linkPattern.matcher(content.toString());

			while (linkMatcher.find()) {
				try {
					result.add(new URL(super.getURL(), linkMatcher.group()).toExternalForm());
				} catch (final MalformedURLException e) {
					// TODO Log exception
				}
			}
		} catch (final Exception e) {
			// TODO Log exception
		} finally {
			super.resetInputStream();
		}

		return result;
	}

	/**
	 * Always returns true.
	 * 
	 * @return true.
	 */
	@Override
	public boolean canCrawl() {
		return true;
	}

	@Override
	protected void close(URLConnection urlConnection) {
	}

	private void parseInputStreamIntoStringBuilder(final StringBuilder content, final String charset) throws IOException {
		final InputStreamReader inputStreamReader = new InputStreamReader(super.getInputStream(), (charset == null? "UTF-8": charset));
		final int BUFFER_SIZE = 2048;
		final char[] buffer = new char[BUFFER_SIZE];
		int length = 0;
		while ((length = inputStreamReader.read(buffer, 0, BUFFER_SIZE)) > -1) {
			content.append(buffer, 0, length);
		}
	}

	@Override
	protected void treatFetchException(final URLConnection urlConnection, final Exception exception) {
		if (!(exception instanceof IOException)) return;
		if (urlConnection == null) return;

		InputStream errorStream = null;
		try {
			try {
				errorStream = ((HttpURLConnection)urlConnection).getErrorStream();
			} catch (final ClassCastException e) {
				errorStream = ((HttpsURLConnectionImpl)urlConnection).getErrorStream();
			}

			if (errorStream == null) return;
			final byte[] buffer = new byte[1024];
			while (errorStream.read(buffer) > 0) {
			}
		} catch (final IOException e) {
		} finally {
			try { if (errorStream != null) errorStream.close(); } catch (final Exception e) {}
		}
	}

	@Override
	protected void lastFetch(final URLConnection urlConnection) {
		if (urlConnection == null) return;
		urlConnection.addRequestProperty("Connection", "close");
	}
}